{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial for Generative Models of Graphs\n",
    "\n",
    "In earlier tutorials we have seen how learned embedding of a graph and/or a node allow applications such as semi-supervised classification for nodes or sentiment analysis. Wouldn’t it be interesting to predict the future evolution of the graph and perform the analysis iteratively?\n",
    "\n",
    "We will need to generate a variety of graph samples, in other words, we need generative models of graphs. Instead of and/or in addition to learning node and edge features, we want to model the distribution of arbitrary graphs. While general generative models can model the density function explicitly and implicitly and generate samples at once or sequentially, we will only focus on explicit generative models for sequential generation here. Typical applications include drug/material discovery, chemical processes, proteomics, etc.\n",
    "\n",
    "## Introduction\n",
    "\n",
    "The primitive actions of mutating a graph in DGL are nothing more than add_nodes and add_edges. That is, if we were to draw a circle of 3 nodes,\n",
    "\n",
    "\n",
    "![](img/introduction.gif)\n",
    "\n",
    "we can simply write the code as:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import dgl\n",
    "\n",
    "g = dgl.DGLGraph()\n",
    "g.add_nodes(1)              # Add node 0\n",
    "g.add_nodes(1)              # Add node 1\n",
    "\n",
    "# Edges in DGLGraph are directed by default.\n",
    "# For undirected edges, we add edges for both directions.\n",
    "g.add_edges([1, 0], [0, 1]) # Add edges (1, 0), (0, 1)\n",
    "g.add_nodes(1)              # Add node 2\n",
    "g.add_edges([2, 1], [1, 2]) # Add edges (2, 1), (1, 2)\n",
    "g.add_edges([2, 0], [0, 2]) # Add edges (2, 0), (0, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Real-world graphs are much more complex. There are many families of graphs, with different sizes, topologies, node types, edge types, and the possibility of multigraphs. Besides, a same graph can be generated in many different orders. Regardless, the generative process entails a few steps:\n",
    "\n",
    "- Encode a changing graph,\n",
    "\n",
    "- Perform actions stochastically,\n",
    "\n",
    "- Collect error signals and optimize the model parameters (If we are training)\n",
    "\n",
    "When it comes to implementation, another important aspect is speed: how do we parallelize the computation given that generating a graph is fundamentally a sequential process?\n",
    "\n",
    "In tutorial, we will first focus on how to train and generate one graph at a time, exploring parallelism within the graph embedding operation, an essential building block. We will end with a simple optimization that delivers a 2x speedup by batching across graphs."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
